#include "ESP01s_Control.h"
#include "Delay.h"

// 指令变量
char usrname[16] = "yang";
char passwd[16] = "12345678";
char payload[64];

// 创建传感器任务句柄
TaskHandle_t xSensorDataHandle = NULL;

// 状态机上下文
typedef struct {
    uint8_t retry_count;
    const uint8_t max_retry;
    esp_state_t prev_state; // 记录上一个状态（用于错误回退）
} esp_context_t;

// 状态机初始化
static esp_context_t ctx = {
    .retry_count = 0,
    .max_retry = 5,
    .prev_state = ESP_STATE_IDLE
};

//uint8_t ESP_index = 0;
esp_state_t ESP_state = ESP_STATE_IDLE;


//// 初始化 payload
//void ESP_BuildPayload(void) {
//    char payload[64];
//    snprintf(payload, sizeof(payload), "AT+CWJAP_DEF=\"%s\",\"%s\"\r\n", usrname, passwd);
//}

void ESP_AutoConnect(void) {
//    ESP_index = 0;
    ESP_state = ESP_STATE_IDLE;
	
	OLED_Clear();
	OLED_ShowString(1, 1, "(^v^)/ hello!");
	OLED_ShowString(2, 1, "Connecting to esp-01s >>>");
    OLED_ShowString(3, 1, "ESP AUTO START");

//	USART_SendString(&USART2_Cfg, (const unsigned char*)"AT+CWMODE_DEF=1\r\n", strlen("AT+CWMODE_DEF=1\r\n"));  // 发送第一条AT指令
//	Delay_ms(500);
    USART_SendString(&USART2_Cfg, (const unsigned char*)"AT+CWJAP?\r\n", strlen("AT+CWJAP?\r\n"));  // 发送第一条AT指令
}

/**
 * @brief  检查esp-01s的状态，并且实现重新联网
 * @param  msg.data
 * @retval 无
 * @note   本来我都写好状态切换指令且可以实用了，奈何状态机是全局变量，需要静态初始化，没办法读取wifi密码，难过...
 *		   现在就是if...else if...else if，毫无程序设计美感可言...
		   改成局部状态机看一下效果！
 */
void ESP_StateTransition(char *resp) {
    USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line55 | esp_state: %d \r\n", ESP_state);
	
	if (strncmp(resp, "HTTP/1.1 200 OK", 15) == 0) {
		USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line58 | esp_state: %d \r\n", ESP_state);
		
//        ESP_index = 5;
		ESP_state = ESP_STATE_HTTP_CONNECT;

		EnterHTTPMode();
		return;
	}
	
	else if ((strncmp(resp, "FAIL", 4) == 0 || strncmp(resp, "ERROR", 5) == 0) || strncmp(resp, "CLOSED", 6) == 0) { /* 失败响应处理 */
		USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line68 | esp_state: %d \r\n", ESP_state);
	
		SYS_RLED_shortBlink();
		//	USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line58\r\n");

		if (++ctx.retry_count < ctx.max_retry) {	// 延时后重发当前指令
			//	USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line62\r\n");

			vTaskDelay(pdMS_TO_TICKS(1000));
			SendATCommand(GetCurrentCommand());
			return;
			
		} else {       								// 彻底失败时重置
			//	USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line68\r\n");
			ResetConnection(); 
			return;
		}
	}
	
	else if(ESP_state == 0 && strncmp(resp, "No AP", 5) == 0 ){	
		USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line89 | esp_state: %d \r\n", ESP_state);
		
		SendWiFiCredentials();
	}
	else if (ESP_state == 0 && (strstr(resp, "+CWJAP:") || strstr(resp, "WIFI CONNECTED"))){
		USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line93 | esp_state: %d \r\n", ESP_state);
		
		StartTCPConnection();
	}
	else if (ESP_state == 1 && strncmp(resp, "WIFI GOT IP", strlen("WIFI GOT IP")) == 0) {
		USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line98 | esp_state: %d \r\n", ESP_state);
		
		StartTCPConnection();
	}
	else if (ESP_state == 2 && (strncmp(resp, "CONNECT", 7) == 0 || strncmp(resp, "ALREADY CONNECTED", 17) == 0)) {
		USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line103 | esp_state: %d \r\n", ESP_state);
		
		EnableTransparentMode();
	}
	else if (ESP_state == 3 && strncmp(resp, "OK", 2) == 0) {
		USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line108 | esp_state: %d \r\n", ESP_state);
		
		PrepareToSend();
	}
	else if (ESP_state == 4 && strncmp(resp, ">", 1) == 0) {
		USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line113 | esp_state: %d \r\n", ESP_state);
		
		EnterHTTPMode();
	}

	USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line158 | esp_state: %d \r\n", ESP_state);
//    memset(resp, 0, strlen(resp));
}

/*--------------- 状态动作封装函数 ---------------*/
static void SendWiFiCredentials(void) {
	USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line164 | esp_state: %d \r\n", ESP_state);
	
    ctx.retry_count = 0;
    SYS_BLLED_shortBlink();
    snprintf(payload, sizeof(payload), "AT+CWJAP_DEF=\"%s\",\"%s\"\r\n", usrname, passwd);
	USART_SendString(&USART2_Cfg, (const unsigned char*)payload, strlen(payload));
    ESP_state = ESP_STATE_WIFI_CONNECT;
    UpdateOLED("Connecting WiFi...");
}

static void StartTCPConnection(void) {
	USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line175 | esp_state: %d \r\n", ESP_state);
    
	ctx.retry_count = 0;
	SYS_BLLED_shortBlink();
	USART_SendString(&USART2_Cfg, (const unsigned char*)"AT+CIPSTART=\"TCP\",\"47.111.20.8\",9080\r\n", strlen("AT+CIPSTART=\"TCP\",\"47.111.20.8\",9080\r\n"));
    ESP_state = ESP_STATE_TCP_CONNECT;
    UpdateOLED("Starting TCP...");
}

static void EnableTransparentMode(void) {
	USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line185 | esp_state: %d \r\n", ESP_state);
	
    ctx.retry_count = 0;
	SYS_BLLED_shortBlink();
	USART_SendString(&USART2_Cfg, (const unsigned char*)"AT+CIPMODE=1\r\n", strlen("AT+CIPMODE=1\r\n"));
    ESP_state = ESP_STATE_TX_PREPARE;
    UpdateOLED("Enabling Transparent...");
}

static void PrepareToSend(void) {
	USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line195 | esp_state: %d \r\n", ESP_state);
	
    ctx.retry_count = 0;
	SYS_BLLED_shortBlink();
	USART_SendString(&USART2_Cfg, (const unsigned char*)"AT+CIPSEND\r\n", strlen("AT+CIPSEND\r\n"));
    ESP_state = ESP_STATE_TRANSPARENT;
    UpdateOLED("Ready to Send!");
}

static void EnterHTTPMode(void) {
	USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line205 | esp_state: %d \r\n", ESP_state);
	
	ctx.retry_count = 0;
	SYS_BLLED_shortBlink();
	ESP_state = ESP_STATE_HTTP_CONNECT;
	UpdateOLED("AUTO READY!");
	
    if (xSensorDataHandle == NULL) {
        xTaskCreate(vTask_ESP01s_SensorData_Push, "SensorPush", 128, NULL, 1, &xSensorDataHandle);
    }
}

static void ResetConnection(void) {
	USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line218 | esp_state: %d \r\n", ESP_state);
	
    ctx.retry_count = 0;
    ESP_state = ESP_STATE_IDLE;
    UpdateOLED("Resetting...");
    vTaskDelay(pdMS_TO_TICKS(1000));
    ESP_AutoConnect(); // 重新触发初始连接
}

//static void StartSensorTask(void) {
//	if (xSensorDataHandle == NULL) {
//		OLED_Clear();
//		OLED_ShowString(1, 1, "AUTO READY!");
//		xTaskCreate(vTask_ESP01s_SensorData_Push, "vTask_ESP01s_SensorData_Push", 128, NULL, 1, &xSensorDataHandle);
//	}
//}

/*--------------- 辅助函数 ---------------*/
// 发送指令的封装函数
static void SendATCommand(const char *cmd) {
	USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line237 | esp_state: %d \r\n", ESP_state);
	
    USART_SendString(&USART2_Cfg, (const unsigned char*)cmd, strlen(cmd));
    OLED_ShowString(3, 1, "Retrying...");
}

static const char* GetCurrentCommand(void) {
	USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line245 | esp_state: %d \r\n", ESP_state);
	
    // 根据当前状态返回对应指令
    switch (ESP_state) {
        case ESP_STATE_WIFI_CONNECT: return payload;
        case ESP_STATE_TCP_CONNECT:  return "AT+CIPSTART=\"TCP\",\"47.111.20.8\",9080\r\n";
        // 其他状态...
        default: return "";
    }
}

static void UpdateOLED(const char *msg) {
	static char state[8];
	switch(ESP_state){
		case 0: strcpy(state,"IDE"); break;
		case 1: strcpy(state,"WIFI"); break;
		case 2: strcpy(state,"TCP"); break;
		case 3: strcpy(state,"TX"); break;
		case 4: strcpy(state,"TRANS"); break;
		case 5: strcpy(state,"HTTP"); break;
		case 6: strcpy(state,"ERROR"); break;
	}
	
    OLED_Clear();
    OLED_ShowString(1, 1, "ESP STATE");
    OLED_ShowString(2, 1, (const char*)state);
    OLED_ShowString(3, 1, msg);
}

/*--------------- 发送状态 ---------------*/
void vTask_ESP01s_SensorData_Push(void *arg) {
    USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line276\r\n");
	
    while (ESP_state == ESP_STATE_HTTP_CONNECT) { // 增加状态判断
        taskENTER_CRITICAL();

        ESP_SendPacket();

        taskEXIT_CRITICAL();

        SYS_BLLED_shortBlink();
        vTaskDelay(pdMS_TO_TICKS(20000)); // 建议用宏保证可读性
    }

    vTaskDelete(NULL); // 自动删除任务
}

void ESP_SendPacket(void) {
	USART_printf(&USART1_Cfg, "[TEST]esp.ctrl.c line293\r\n");
	
    char payload[MAX_MSG_LEN];

    // 1. 采集数据
    uint16_t adc_val = AD_GetValue(ADC_Channel_1);
    int payload_len = snprintf(payload, sizeof(payload), "GET /0 HTTP/1.1\r\nuser-agent: STM32\r\n\r\n[PESS CH1:%d]",
                               adc_val);

    // 2. 发送数据至服务器
    payload[payload_len] = '\0';
    USART_SendString(&USART2_Cfg, (const unsigned char*)payload, strlen(payload));

    // 3. 发送数据至OLED
    OLED_Clear();
    OLED_ShowString(1, 1, "PESS CH1:");
    OLED_ShowUnsignedNum(2, 1, adc_val, 4);

    // 4. 根据传感器反馈值控制小灯
    if (adc_val >= 2000) {
        GPIO_WriteBit(SNR_LED_PORT, SNR_LED_PIN, (BitAction)LED_OFF);
    } else {
        GPIO_WriteBit(SNR_LED_PORT, SNR_LED_PIN, (BitAction)LED_ON);
    }
}
